﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;

namespace csharpuniversity.ErrorTracking
{
    /// <summary>
    /// Author: Ted Kolovos (MCSD.NET, PMP) ©2009 EzBiz, LLC
    /// FAQ (w/ usage examples): http://www.CSharpUniversity.com/aspneterrorhandler
    /// 
    /// Summary: The csharpuniversity.ErrorTracking library lets you
    /// easily keep track of errors that occur in a production ASP.NET
    /// website.  With the easy to use ErrorLog class your application
    /// can have exception handling and reporting within minutes.
    /// 
    /// Relevant tutorials:
    /// http://www.csharpuniversity.com/2009/05/29/how-to-use-adonet-with-parameters-in-aspnet-to-insert-a-record-into-a-sql-server-database/
    /// http://www.csharpuniversity.com/2009/05/25/how-to-use-adonet-with-parameters-in-aspnet-to-query-a-sql-server-database/
    /// 
    /// Licensed under the Apache License, Version 2.0 (the "License");
    /// you may not use this file except in compliance with the License.
    /// You may obtain a copy of the License at
    /// http://www.apache.org/licenses/LICENSE-2.0
    ///
    /// Unless required by applicable law or agreed to in writing, software
    /// distributed under the License is distributed on an "AS IS" BASIS,
    /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    /// See the License for the specific language governing permissions and
    /// limitations under the License.
    /// </summary>
    public class ErrorLog
    {
        public static int saveError(string DBConnString, string ErrMessage, DateTime TimeOccured,
            string StackTrace, string Location,
            string ClientIP, string ServerName,
            string Custom1, string Custom2,
            string Custom3, string Custom4,
            string Custom5)
        {
            using (SqlConnection dbconn = new SqlConnection(DBConnString))
            {
                SqlCommand cmd = new SqlCommand();
                SqlParameter param;
                string sqlQuery = "INSERT into [errorlog] (error_message, time_occured, stacktrace, location, clientip, servername, custom1, custom2, custom3, custom4, custom5) values (@error_message,@time_occured, @stacktrace, @location, @clientip, @servername, @custom1, @custom2, @custom3, @custom4, @custom5); SET @Identity = Scope_Identity();";

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@error_message";
                param.Value = ErrMessage;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.DateTime;
                param.ParameterName = "@time_occured";
                param.Value = TimeOccured;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@stacktrace";
                if (string.IsNullOrEmpty(StackTrace))
                    param.Value = DBNull.Value;
                else
                    param.Value = StackTrace;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@location";
                if (string.IsNullOrEmpty(Location))
                    param.Value = DBNull.Value;
                else
                    param.Value = Location;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@clientip";
                if (string.IsNullOrEmpty(ClientIP))
                    param.Value = DBNull.Value;
                else
                    param.Value = ClientIP;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@servername";
                if (string.IsNullOrEmpty(ServerName))
                    param.Value = DBNull.Value;
                else
                    param.Value = ServerName;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@custom1";
                if (string.IsNullOrEmpty(Custom1))
                    param.Value = DBNull.Value;
                else
                    param.Value = Custom1;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@custom2";
                if (string.IsNullOrEmpty(Custom2))
                    param.Value = DBNull.Value;
                else
                    param.Value = Custom2;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@custom3";
                if (string.IsNullOrEmpty(Custom3))
                    param.Value = DBNull.Value;
                else
                    param.Value = Custom3;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@custom4";
                if (string.IsNullOrEmpty(Custom4))
                    param.Value = DBNull.Value;
                else
                    param.Value = Custom4;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = "@custom5";
                if (string.IsNullOrEmpty(Custom5))
                    param.Value = DBNull.Value;
                else
                    param.Value = Custom5;
                cmd.Parameters.Add(param);

                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.Int32;
                param.ParameterName = "@Identity";
                param.Direction = ParameterDirection.Output;
                cmd.Parameters.Add(param);

                cmd.CommandText = sqlQuery;
                cmd.Connection = dbconn;
                dbconn.Open();
                cmd.ExecuteNonQuery();

                return (int)cmd.Parameters["@Identity"].Value;
            }
        }

        public DataSet getErrors(string DBConnString, bool OldestFirst,
            int MaxNumOfRecords,
            int ErrorId, string ErrMessage,
            DateTime StartDate, DateTime EndDate,
            bool PartialMatch,
            string StackTrace, string Location,
            string ClientIP, string ServerName,
            string Custom1, string Custom2,
            string Custom3, string Custom4,
            string Custom5)
        {
            SqlDataAdapter dbadapter = null;
            DataSet returnDS = new DataSet();

            using (SqlConnection dbconn = new SqlConnection(DBConnString))
            {
                string where = string.Empty;
                SqlCommand cmd = new SqlCommand();
                SqlParameter param;

                string sqlQuery = "select ";
                if (MaxNumOfRecords > 0)
                    sqlQuery += string.Format("TOP {0} ", MaxNumOfRecords);
                sqlQuery += "* from [errorlog] ";

                if (StartDate != DateTime.MinValue &&
                    EndDate != DateTime.MinValue)
                {
                    if (string.IsNullOrEmpty(where))
                        where = "where ";
                    else
                        where = "and ";
                    sqlQuery += where + "time_occured between @start_date and @end_date ";
                    param = cmd.CreateParameter();
                    param.DbType = System.Data.DbType.DateTime;
                    param.ParameterName = "@start_date";
                    param.Value = StartDate;
                    cmd.Parameters.Add(param);
                    param = cmd.CreateParameter();
                    param.DbType = System.Data.DbType.DateTime;
                    param.ParameterName = "@end_date";
                    param.Value = EndDate;
                    cmd.Parameters.Add(param);
                }

                if (ErrorId != 0)
                {
                    if (string.IsNullOrEmpty(where))
                        where = "where ";
                    else
                        where = "and ";
                    sqlQuery += where + "error_id = @error_id ";
                    param = cmd.CreateParameter();
                    param.DbType = System.Data.DbType.Int32;
                    param.ParameterName = "@error_id";
                    param.Value = ErrorId;
                    cmd.Parameters.Add(param);
                }

                CreateStringParam(ref sqlQuery, "error_message", ErrMessage,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "stacktrace", StackTrace,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "location", Location,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "clientip", ClientIP,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "servername", ServerName,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "custom1", Custom1,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "custom2", Custom2,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "custom3", Custom3,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "custom4", Custom4,
                    cmd, PartialMatch, ref where);
                CreateStringParam(ref sqlQuery, "custom5", Custom5,
                    cmd, PartialMatch, ref where);

                if(OldestFirst)
                    sqlQuery += "order by time_occured asc ";
                else
                    sqlQuery += "order by time_occured desc ";

                cmd.CommandText = sqlQuery;
                cmd.Connection = dbconn;
                dbadapter = new SqlDataAdapter(cmd);

                dbadapter.Fill(returnDS);
            }

            return returnDS;
        }

        private void CreateStringParam(ref string sqlQuery,
            string ColumnName, string ParamValue,
            SqlCommand cmd, bool PartialMatch,
            ref string where)
        {
            SqlParameter param;

            if (!string.IsNullOrEmpty(ParamValue))
            {
                if (string.IsNullOrEmpty(where))
                    where = "where ";
                else
                    where = "and ";
                if (PartialMatch)
                    sqlQuery += where + string.Format("{0} like @{0} ", ColumnName);
                else
                    sqlQuery += where + string.Format("{0} = @{0} ", ColumnName);
                param = cmd.CreateParameter();
                param.DbType = System.Data.DbType.String;
                param.ParameterName = string.Format("@{0}", ColumnName);
                if (PartialMatch)
                    param.Value = string.Format("%{0}%", ParamValue);
                else
                    param.Value = ParamValue;
                cmd.Parameters.Add(param);
            }
        }

        public static string getVersion()
        {
            System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();
            System.Reflection.AssemblyName assemblyname = assembly.GetName();
            return assemblyname.Version.ToString();
        }
    }
}
